package com.lobaby.tools.common.utils;

import org.apache.commons.exec.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
public class CommandUtils {
	private final static Logger LOGGER = LoggerFactory.getLogger(CommandUtils.class);

	private static final String DEFAULT_CHARSET = "UTF-8";
	
	public static final String REPLACE_FILE_CONTENT_WINDOWS_PREFIX = "powershell -Command \"(gc sourcefile) ";
	
	public static final String REPLACE_FILE_CONTENT_WINDOWS_SUFFIX = " | Out-File -Encoding utf8 targetfile\"";
	
	public static final String REPLACE_FILE_CONTENT_LINUX_PREFIX = "sed ";
	
	public static final String REPLACE_FILE_CONTENT_LINUX_SUFFIX = " sourcefile > targetfile"; 
	
	public static void replaceFileContent(Map<String, String> param) {
		List<String> commands = new ArrayList<>();
		
		String osname = System.getProperties().getProperty("os.name");
		String command = new String();
		if (osname.toLowerCase().indexOf("linux") != -1) {
			for (String key : param.keySet()) {
				if (!key.equals("sourcefile") && !key.equals("targetfile")) {
					commands.add("-e");
					commands.add("\"s/" + key + "/" + param.get(key) + "/g\"");
				}
			}
			command = REPLACE_FILE_CONTENT_LINUX_PREFIX + String.join(" ", commands) 
						+ REPLACE_FILE_CONTENT_WINDOWS_SUFFIX.replace("sourcefile", param.get("sourcefile")).replace("targetfile", param.get("targetfile"));
		} else {
			for (String key : param.keySet()) {
				if (!key.equals("sourcefile") && !key.equals("targetfile")) {
					commands.add("-replace");
					commands.add("'" + key + "','" + param.get(key) + "'");
				}
			}
			command = REPLACE_FILE_CONTENT_WINDOWS_PREFIX.replace("sourcefile", param.get("sourcefile")) + String.join(" ", commands) 
						+ REPLACE_FILE_CONTENT_WINDOWS_SUFFIX.replace("targetfile", param.get("targetfile"));
		}
		
		try {
			LOGGER.info("==============> 执行命令：" + command);
			String result = exeCommand(command);
			LOGGER.info("==============> 命令执行结果：" + result);
		} catch (IOException e) {
//			LOGGER.error("", e);
		}
	}

	private static int doWaitFor(Process process) {
		InputStream in = null;
		InputStream err = null;
		
		int exitValue = -1;
		try {
			in = process.getInputStream();
			err = process.getErrorStream();
			boolean isfinshed = false;
			
			while (!isfinshed) {
				try {
					while (in.available() > 0) {
						Character c = new Character((char) in.read());
						System.out.println(c);
					}
					while (err.available() > 0) {
						Character c = new Character((char) err.read());
						System.out.println(c);
					}
					exitValue = process.exitValue();
					isfinshed = true;
				} catch (Exception e) {
					LOGGER.error("", e);
					Thread.currentThread();
					Thread.sleep(500);  
				}
			}
		} catch (Exception e) {
			LOGGER.error("", e);
		} finally {  
            try {  
                if (in != null) {  
                    in.close();  
                }  
            } catch (IOException e) {  
            	LOGGER.error("等待进程处理错误", e);
            }  
            if (err != null) {  
                try {  
                    err.close();  
                } catch (IOException e) {  
                	LOGGER.error("等待进程处理错误", e);  
                }  
            }  
        }
		
		return exitValue;
	}
	
	public static String exeCommand(String commandPath, String... params) throws IOException {
		List<String> command = new ArrayList<>();
		command.add(commandPath);
		List<String> collect = Stream.of(params).collect(Collectors.toList());
		
		command.addAll(collect);
		return exeCommand(String.join(" ", collect));
	}
	/**
     * 执行指定命令
     * 
     * @param command 命令
     * @return 命令执行完成返回结果
     * @throws IOException 失败时抛出异常，由调用者捕获处理
     */
    public static String exeCommand(String command) throws IOException {
        try {
        	ByteArrayOutputStream out = new ByteArrayOutputStream();
            int exitCode = exeCommand(command, out);
            if (exitCode == 0) {
                LOGGER.info("命令运行成功！");
            } else {
                System.out.println("命令运行失败！");
            }
            
            return out.toString(DEFAULT_CHARSET);
        } catch (Exception e) {
        	LOGGER.error("", e);
        	return "";
        }
    }
    
    /**
     * 执行指定命令，输出结果到指定输出流中
     * 
     * @param command 命令
     * @param out 执行结果输出流
     * @return 执行结果状态码：执行成功返回0
     * @throws ExecuteException 失败时抛出异常，由调用者捕获处理
     * @throws IOException 失败时抛出异常，由调用者捕获处理
     */
    public static int exeCommand(String command, OutputStream out) throws ExecuteException, IOException {
        CommandLine commandLine = CommandLine.parse(command);
        PumpStreamHandler pumpStreamHandler = null;
        if (null == out) {
            pumpStreamHandler = new PumpStreamHandler();
        } else {
            pumpStreamHandler = new PumpStreamHandler(out);
        }

        // 设置超时时间为10秒
        ExecuteWatchdog watchdog = new ExecuteWatchdog(10000);

        DefaultExecutor executor = new DefaultExecutor();
        executor.setStreamHandler(pumpStreamHandler);
        executor.setWatchdog(watchdog);

        return executor.execute(commandLine);
    }
}
